package net.towee.client.com.app;

import net.towee.client.ToweeGinjector;
import net.towee.client.com.dashboard.DashBoard;
import net.towee.client.com.lobby.Lobby;
import net.towee.client.com.repo.Repository;
import net.towee.client.com.stuff.Stuff;
import net.towee.client.event.UserAccepted;
import net.towee.client.event.UserAcceptedHandler;
import net.towee.client.event.core.ShowComponentEvent;
import net.towee.client.event.core.ShowComponentEventHandler;
import net.towee.client.history.HistoryManager;
import net.towee.client.managers.AccountHelper;
import net.towee.client.managers.AccountsManager;
import net.towee.model.account.AccountData;

import com.google.common.base.Strings;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.inject.client.AsyncProvider;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.inject.Inject;

/**
 * Start point of client application.
 * 
 * @author c58
 */
public class AppController implements Presenter {

	/**
	 * Display interface consists of three main blocks: 1. Top panel(title).
	 * Contain navigation buttons, logo and other... 2. Body. The main block of
	 * interface. 3. Bottom. Contain copyrights, useful links, etc.
	 * 
	 * @author c58
	 */
	public interface Display extends IsWidget {
		HasWidgets getConnectionStataContainer();
		
		HasWidgets getTopContainer();

		HasWidgets getBodyContainer();

		HasWidgets getBottomContainer();
		
		HasClickHandlers getFeedbackButton();
	}

	/**
	 * The enum of main components
	 * 
	 * @author c58
	 */
	public enum Component {
		ME, STUFF, DASHBOARD, REPO, LOBBY
	}

	// final injected objects
	private final HandlerManager eventBus;
	private final ToweeGinjector injector;
	private final Display display;
	private final AccountsManager accountManager;
	private final HistoryManager history;
	private final ConnectionController connController;
	private final AccountHelper accountHelper;
	
	// Code splitting points
	@Inject AsyncProvider<Lobby> lobbyProvider;
	@Inject AsyncProvider<DashBoard> dashboardProvider;
	@Inject AsyncProvider<Repository> repoProvider;
	@Inject AsyncProvider<Stuff> stuffProvider;

	@Inject
	public AppController(HandlerManager eventBus, ToweeGinjector injector, Display display,
			AccountsManager accountManager, HistoryManager history, ConnectionController connController,
			AccountHelper helper) {
		this.eventBus = eventBus;
		this.injector = injector;
		this.display = display;
		this.accountManager = accountManager;
		this.history = history;
		this.accountHelper = helper;
		this.connController = connController;
		
		createSystemHandlers();
	}

	private void createSystemHandlers() {
		display.getFeedbackButton().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				injector.getFeedbackPanel().go(null);
			}
		});
		
		eventBus.addHandler(UserAccepted.TYPE, new UserAcceptedHandler() {
			@Override
			public void onAccountAccepted(AccountData acc) {
					if (acc.getAccountIdentity().getNickName() == null)
						eventBus.fireEvent(new ShowComponentEvent(Component.LOBBY));
					else {
						if( !History.getToken().isEmpty() ) 
							History.fireCurrentHistoryState();
						else
							eventBus.fireEvent(new ShowComponentEvent(Component.DASHBOARD));
					}
					
					// Check user remembered and ask for remembering
					if( Strings.isNullOrEmpty( Cookies.getCookie("__towee_rem_id") ))
						injector.getRememberForm().go(null);
			}
		});

		eventBus.addHandler(ShowComponentEvent.TYPE, new ShowComponentEventHandler() {
			@Override
			public void onShowComponent(Component component, String... params) {
				switch (component) {
				case LOBBY:
					if(accountHelper.getAccount().getAccountIdentity().getNickName() != null)
						eventBus.fireEvent(new ShowComponentEvent(Component.DASHBOARD));
					else					
						lobbyProvider.get(new AsyncCallback<Lobby>(){
							@Override
							public void onFailure(Throwable caught) {}
							@Override
							public void onSuccess(Lobby result) {
								result.go(display.getBodyContainer());
							}
						});
						break;
				case DASHBOARD:
					dashboardProvider.get(new AsyncCallback<DashBoard>(){
						@Override
						public void onFailure(Throwable caught) {}
						@Override
						public void onSuccess(DashBoard result) {
							result.go(display.getBodyContainer());
						}
					});
					break;
				case REPO:
					repoProvider.get(new AsyncCallback<Repository>(){
						@Override
						public void onFailure(Throwable caught) {}
						@Override
						public void onSuccess(Repository result) {
							result.go(display.getBodyContainer());
						}
					});
					break;
				case STUFF:
					stuffProvider.get(new AsyncCallback<Stuff>(){
						@Override
						public void onFailure(Throwable caught) {}
						@Override
						public void onSuccess(Stuff result) {
							result.go(display.getBodyContainer());
						}
					});
					break;
				}
			}
		});
	}

	@Override
	public void go(HasWidgets container) {
		// Create top and bottom panel
		connController.go( display.getConnectionStataContainer() );
		injector.getTopPanel().go(display.getTopContainer());

		// Initialize account
		accountManager.initializeAccount();

		// Add main app to root container
		container.add(display.asWidget());
	}
}
